/** \file    multiio.cpp
  * \brief   Read/write using multiple readers/writers.
  * \date    2003
  * \author  Fedor Chelnokov
  * \version $Header: /home/cscom1r4/cvsroot/cs/imglib/src/multiio.cpp,v 1.2 2004/04/30 19:13:30 cscom1r4 Exp $
  */

#include "imglib/io.h"
#include <algorithm>
#include <numeric>
#include <xtd/functional>

namespace img {

/////////////////
// multireader //
/////////////////

void multireader::insert(reader * r)
{
	_readers.push_back(r);
}

multireader::~multireader()
{
	std::for_each(_readers.begin(), _readers.end(), xtd::deleter());
}

bool multireader::ping(const std::string & path, file_info * info) const
{
	std::vector<reader*>::const_iterator i;
	for (i = _readers.begin(); i != _readers.end(); ++i)
		if ((*i)->ping(path, info))
			return true;
	return false;
}

bool multireader::ping(const std::string & path, const std::string & format, file_info * info) const
{
	std::vector<reader*>::const_iterator i;
	for (i = _readers.begin(); i != _readers.end(); ++i)
		if ((*i)->ping(path, format, info))
			return true;
	return false;
}

struct fast_ping_logical_or : std::binary_function<bool, reader*, bool>
{
	bool operator () (bool lhs, reader * rhs) {
		return lhs || rhs->fast_ping();
	}
};

bool multireader::fast_ping() const
{
	return std::accumulate(_readers.begin(), _readers.end(), 
		false, fast_ping_logical_or());
}

void multireader::read(const std::string & path, byte_image & img) const
{
	assert(_readers.begin() != _readers.end());
	std::vector<reader*>::const_iterator i;
	for (i = _readers.begin(); i+1 != _readers.end(); ++i) {
		if ((*i)->fast_ping() && !(*i)->ping(path))
			continue;
		try {
			(*i)->read(path, img);
			return;
		}
		catch (const io_error &) {}
	}
	(*i)->read(path, img);
}

void multireader::read(const std::string & path, const std::string & format, byte_image & img) const
{
	assert(_readers.begin() != _readers.end());
	std::vector<reader*>::const_iterator i;
	for (i = _readers.begin(); i+1 != _readers.end(); ++i) {
		if ((*i)->fast_ping() && !(*i)->ping(path, format))
			continue;
		try {
			(*i)->read(path, format, img);
			return;
		}
		catch (const io_error &) {}
	}
	(*i)->read(path, format, img);
}

void multireader::formats(ext_vec & f) const
{
	std::vector<reader*>::const_iterator i = _readers.begin();
	if (i == _readers.end()) {
		f.clear();
		return;
	}
	(*i)->formats(f);
	for (++i; i != _readers.end(); ++i) {
		ext_vec e;
		(*i)->formats(e);
		f.unite(e);
	}
}

/////////////////
// multiwriter //
/////////////////

void multiwriter::insert(writer * w)
{
	_writers.push_back(w);
}

multiwriter::~multiwriter()
{
	std::for_each(_writers.begin(), _writers.end(), xtd::deleter());
}

size_t multiwriter::write(const std::string & path, const std::string & format, const byte_image & img, bool alpha)
{
	assert(_writers.begin() != _writers.end());
	std::vector<writer*>::const_iterator i;
	for (i = _writers.begin(); i+1 != _writers.end(); ++i) {
		try {
			return (*i)->write(path, format, img, alpha);
		}
		catch (const io_error &) {}
	}
	return (*i)->write(path, format, img, alpha);
}

void multiwriter::formats(ext_vec & f) const
{
	std::vector<writer*>::const_iterator i = _writers.begin();
	if (i == _writers.end()) {
		f.clear();
		return;
	}
	(*i)->formats(f);
	for (++i; i != _writers.end(); ++i) {
		ext_vec e;
		(*i)->formats(e);
		f.unite(e);
	}
}

} //namespace img
